import 'package:dio/dio.dart';

class Http {
  static final Http _instance = Http._internal();

  factory Http() => _instance;

  static late final Dio dio;

  List<CancelToken> pendingRequests = [];

  Http._internal() {
    // BaseOptions、Options、RequestOptions 都可以配置参数，优先级别依次递增，且可以根据优先级别覆盖参数
    BaseOptions options = BaseOptions();

    dio = Dio(options);

    // // 添加request拦截器
    // dio.interceptors.add(RequestInterceptor());
    // // 签名拦截器
    // dio.interceptors.add(SignatureInterceptor());
    // // 添加token拦截器
    // dio.interceptors.add(TokenInterceptor());
    // // 添加error拦截器
    // dio.interceptors.add(ErrorInterceptor());
    // // 添加cache拦截器
    // dio.interceptors.add(NetCacheInterceptor());
    // // 添加log拦截器
    // dio.interceptors.add(HttpLogInterceptor());
    // 添加retry拦截器
    // dio.interceptors.add(RetryOnConnectionChangeInterceptor(
    //   requestRetries: DioConnectivityRequestRetries(
    //     dio: dio,
    //     connectivity: Connectivity(),
    //   ),
    // ));

    //在调试模式下需要抓包调试，所以我们使用代理，并禁用HTTPS证书校验
    // if (GlobalConfig.enableProxy) {
    //   _buildProxy();
    // }
  }

  /// 构建proxy
  // void _buildProxy() async {
  //   var ip = PrefsUtil().getString(PrefsKeys.proxyIpKey);
  //   var port = PrefsUtil().getString(PrefsKeys.proxyPortKey);
  //   if (ip != null && ip.isNotEmpty && port != null && port.isNotEmpty) {
  //     var adapter = IOHttpClientAdapter(
  //       createHttpClient: () {
  //         final HttpClient client = HttpClient();
  //         client.findProxy = (uri) {
  //           // Proxy all request to localhost:8888.
  //           // Be aware, the proxy should went through you running device,
  //           // not the host platform.
  //           return 'PROXY $ip:$port';
  //         };
  //         // You can test the intermediate / root cert here. We just ignore it.
  //         client.badCertificateCallback = (cert, host, port) => true;
  //         return client;
  //       },
  //     );
  //     dio.httpClientAdapter = adapter;
  //   }
  // }

  // 初始化公共属性
  // [baseUrl] 地址前缀
  // [connectTimeout] 连接超时赶时间
  // [receiveTimeout] 接收超时赶时间
  // [interceptors] 基础拦截器
  // [httpClientAdapter] http代理设置
  void init({
    String? baseUrl,
    int connectTimeout = 15000,
    int receiveTimeout = 15000,
    int sendTimeout = 15000,
    Map<String, String>? headers,
    List<Interceptor>? interceptors,
    HttpClientAdapter? httpClientAdapter,
  }) {
    dio.options = dio.options.copyWith(
      baseUrl: baseUrl,
      connectTimeout: Duration(milliseconds: connectTimeout),
      receiveTimeout: Duration(milliseconds: receiveTimeout),
      sendTimeout: Duration(milliseconds: sendTimeout),
      headers: headers ?? const {},
    );
    if (interceptors != null && interceptors.isNotEmpty) {
      dio.interceptors.addAll(interceptors);
    }
    if (httpClientAdapter != null) {
      dio.httpClientAdapter = httpClientAdapter;
    }
  }

  // 关闭所有 pending dio
  void cancelRequests() {
    pendingRequests.map((token) => token.cancel('dio cancel'));
  }

  // 获取cancelToken , 根据传入的参数查看使用者是否有动态传入cancel，没有就生成一个
  CancelToken createDioCancelToken(CancelToken? cancelToken) {
    CancelToken token = cancelToken ?? CancelToken();
    pendingRequests.add(token);
    return token;
  }

  Future get(
    String path, {
    Map<String, dynamic>? params,
    Options? options,
    CancelToken? cancelToken,
    bool refresh = false,
    bool noCache = false,
    String? cacheKey,
    bool cacheDisk = false,
  }) async {
    Options requestOptions = options ?? Options();
    requestOptions = requestOptions.copyWith(
      extra: {
        "refresh": refresh,
        "noCache": noCache,
        "cacheKey": cacheKey,
        "cacheDisk": cacheDisk,
      },
    );

    CancelToken dioCancelToken = createDioCancelToken(cancelToken);
    Response response = await dio.get(
      path,
      queryParameters: params,
      options: requestOptions,
      cancelToken: dioCancelToken,
    );
    pendingRequests.remove(dioCancelToken);
    return response.data;
  }

  Future post(
    String path, {
    Map<String, dynamic>? params,
    data,
    Options? options,
    CancelToken? cancelToken,
  }) async {
    Options requestOptions = options ?? Options();
    CancelToken dioCancelToken = createDioCancelToken(cancelToken);
    Response response = await dio.post(
      path,
      data: data,
      queryParameters: params,
      options: requestOptions,
      cancelToken: dioCancelToken,
    );
    pendingRequests.remove(dioCancelToken);
    return response.data;
  }

  Future put(
    String path, {
    data,
    Map<String, dynamic>? params,
    Options? options,
    CancelToken? cancelToken,
  }) async {
    Options requestOptions = options ?? Options();
    CancelToken dioCancelToken = createDioCancelToken(cancelToken);
    Response response = await dio.put(
      path,
      data: data,
      queryParameters: params,
      options: requestOptions,
      cancelToken: dioCancelToken,
    );
    pendingRequests.remove(dioCancelToken);
    return response.data;
  }

  Future patch(
    String path, {
    data,
    Map<String, dynamic>? params,
    Options? options,
    CancelToken? cancelToken,
  }) async {
    Options requestOptions = options ?? Options();
    CancelToken dioCancelToken = createDioCancelToken(cancelToken);
    Response response = await dio.patch(
      path,
      data: data,
      queryParameters: params,
      options: requestOptions,
      cancelToken: dioCancelToken,
    );
    pendingRequests.remove(dioCancelToken);
    return response.data;
  }

  Future delete(
    String path, {
    data,
    Map<String, dynamic>? params,
    Options? options,
    CancelToken? cancelToken,
  }) async {
    Options requestOptions = options ?? Options();
    CancelToken dioCancelToken = createDioCancelToken(cancelToken);
    Response response = await dio.delete(
      path,
      data: data,
      queryParameters: params,
      options: requestOptions,
      cancelToken: dioCancelToken,
    );
    pendingRequests.remove(dioCancelToken);
    return response.data;
  }
}
